DataGridEditorController = Class.create({
  buildEditor: function (name, columnDefinition) { },
  buildViewer: function (name, columnDefinition) { },
  attachContentHandler: function (dataGrid, cell, handlerInstance) {
    handlerInstance._dataGrid = dataGrid;
    handlerInstance._cell = cell;
    
    if (handlerInstance._columnDefinition.contextMenu) {
      var contextMenuButtonContainer = new Element("div", {className: "dataGridCellContextMenuButtonContainer"});
      var contextMenuButton = new Element("span", {className: "dataGridCellContextMenuButton"});
      var editorContainer = new Element("div", {className: "dataGridCellEditorContainer"});
        cell.addClassName('dataGridContextMenuCell');
      
      Event.observe(contextMenuButton, "click", dataGrid._contextMenuButtonClickListener);

      contextMenuButtonContainer.appendChild(contextMenuButton);
      editorContainer.appendChild(handlerInstance);
      cell.appendChild(editorContainer);
      cell.appendChild(contextMenuButtonContainer);
    } else {
      cell.appendChild(handlerInstance);
    }
    
    var row = this.getEditorRow(handlerInstance);
    var column = this.getEditorColumn(handlerInstance);
    dataGrid._setCellContentHandler(row, column, handlerInstance);
    
    if (handlerInstance._columnDefinition.hidden == true) 
      this.hide(handlerInstance);
    else
      this.show(handlerInstance);
    
    var selectable = handlerInstance._columnDefinition.selectable;
    if (selectable == false)
      this.setSelectable(handlerInstance, false);
    
    return handlerInstance;
  },
  detachContentHandler: function (handlerInstance) {
    var row = this.getEditorRow(handlerInstance);
    var column = this.getEditorColumn(handlerInstance);
    handlerInstance._dataGrid._unsetCellContentHandler(row, column);
    handlerInstance._dataGrid = undefined;
    var cell = handlerInstance._cell;

    var children = cell.childElements();
    
    for (var i = children.length - 1; i >= 0; i--) {
      var child = children[i];
      child.parentNode.removeChild(child);
    }
    // For unknown reason the following line doesn't work in all cases.
//    cell.childElements().invoke('remove');
  },  
  destroyHandler: function (handlerInstance) { 
    handlerInstance._editable = undefined;
    handlerInstance._dataType = undefined;
    handlerInstance._name = undefined;
    handlerInstance._cell = undefined;
    handlerInstance._columnDefinition = undefined;
    
    if (handlerInstance._fieldValue) {
      handlerInstance.removeChild(handlerInstance._fieldValue);
      handlerInstance._fieldValue = undefined;
    }
    
    if (handlerInstance._fieldContent) {
      handlerInstance.removeChild(handlerInstance._fieldContent);
      handlerInstance._fieldContent = undefined;
    }
  },
  getEditable: function (handlerInstance) {
    return handlerInstance._editable;
  },
  setEditable: function (handlerInstance, editable) {
    if (handlerInstance._editable == editable)
      return handlerInstance;
    if ((this.getMode(handlerInstance) == DataGridControllers.EDITMODE_ONLY_EDITABLE) && (editable == false))
      return handlerInstance;
    if ((this.getMode(handlerInstance) == DataGridControllers.EDITMODE_NOT_EDITABLE) && (editable == true))
      return handlerInstance;
    
    var dataGrid = handlerInstance._dataGrid;
    var cell = handlerInstance._cell;
    var visible = this.isVisible(handlerInstance); 
    var cellValue = this.getEditorValue(handlerInstance);
    
    this.detachContentHandler(handlerInstance);
    
    var newHandler = editable == true ? this.buildEditor(handlerInstance._name, handlerInstance._columnDefinition) : this.buildViewer(handlerInstance._name, handlerInstance._columnDefinition);
    this.attachContentHandler(dataGrid, cell, newHandler);
    
    if (visible) 
      this.show(newHandler);
    else 
      this.hide(newHandler);
    
    this.setEditorValue(newHandler, cellValue);
    this.destroyHandler(handlerInstance);

    return newHandler;
  },
  getEditorValue: function (handlerInstance) {},
  setEditorValue: function (handlerInstance, value) {},
  getDisplayValue: function (handlerInstance) {
    if (this.getEditable(handlerInstance) != true)
      return handlerInstance._fieldContent.innerHTML;
    else
      return this.getEditorValue(handlerInstance);
  },
  disableEditor: function (handlerInstance) {},
  enableEditor: function (handlerInstance) {},
  enableEditor: function (handlerInstance) {},
  isDisabled: function (handlerInstance) {},
  hide: function (handlerInstance) {
    handlerInstance._cell.hide();
  },
  show: function (handlerInstance) {
    handlerInstance._cell.show();
  },
  isVisible: function (handlerInstance) {
    return handlerInstance._cell.visible();
  },
  setSelectable: function (handlerInstance, selectable) {
    if (selectable == true) {
      handlerInstance.onselectstart = undefined;
      handlerInstance.unselectable = "off";
      handlerInstance.style.MozUserSelect = "text";
    } else {
      handlerInstance.onselectstart = function(){ return false; };
      handlerInstance.unselectable = "on";
      handlerInstance.style.MozUserSelect = "none";
    }
  },
  getMode: function () { },
  getDataType: function () { },
  changeParamName: function (handlerInstance, name) {
    if (handlerInstance._editable) {
      handlerInstance.name = name;
    } else {
      handlerInstance._name = name;
      if (handlerInstance._fieldValue) {
        handlerInstance._fieldValue.name = name;
      }
    }
  },
  focus: function (handlerInstance) {
    Form.Element.focus(handlerInstance);
  },
  getDataGridComponent: function (handlerInstance) {
    return handlerInstance._dataGrid;
  },
  getEditorRow: function (handlerInstance) {
    return handlerInstance._dataGrid._getCellEditorRow(handlerInstance);
  },
  getEditorColumn: function (handlerInstance) {
    return handlerInstance._dataGrid._getCellEditorColumn(handlerInstance);
  },
  _createEditorElement: function (elementName, name, className, attributes, columnDefinition) {
    var editor = new Element(elementName, Object.extend(attributes||{}, {className: "dataGridCellEditor" + (className ? ' ' + className : '')}));
    
    if (columnDefinition.editorClassNames) {
      var classNames = columnDefinition.editorClassNames.split(' ');
      for (var i = 0, l = classNames.length; i < l; i++) {
        editor.addClassName(classNames[i]);
      }
    }
    
    editor._editable = true;
    editor._dataType = this.getDataType();
    editor._name = name;
    editor._columnDefinition = columnDefinition;
    return editor;
  },
  _createViewerElement: function (elementName, name, className, attributes, columnDefinition) {
    var viewer = new Element(elementName, Object.extend(attributes||{}, {className: "dataGridCellViewer" + (className ? ' ' + className : '')}));
    
    if (columnDefinition.viewerClassNames) {
      var classNames = columnDefinition.viewerClassNames.split(' ');
      for (var i = 0, l = classNames.length; i < l; i++) {
        viewer.addClassName(classNames[i]);
      }
    }
    
    viewer._editable = false;
    viewer._dataType = this.getDataType();
    viewer._name = name;
    viewer._columnDefinition = columnDefinition;
    
    viewer._fieldValue = new Element("input", {type: "hidden", name: name});
    viewer._fieldContent = new Element("span"); 
    viewer.appendChild(viewer._fieldValue);
    viewer.appendChild(viewer._fieldContent); 
    
    return viewer;
  },
  _setViewerValue: function (viewer, value, displayValue) {
    if (value == undefined||value==null) {
      viewer._fieldValue.value = '';
      viewer._fieldContent.innerHTML = '';
    } else {
      viewer._fieldValue.value = value;
      viewer._fieldContent.innerHTML = displayValue ? displayValue : String(value).escapeHTML();
    }
  },
  _getViewerValue: function (viewer) {
    return viewer._fieldValue.value;
  },
  _fireValueChange: function (handlerInstance, newValue) {
    handlerInstance._dataGrid.fire("cellValueChange", {
      dataGridComponent: handlerInstance._dataGrid,
      fieldType: handlerInstance._dataType,
      column: this.getEditorColumn(handlerInstance),
      row: this.getEditorRow(handlerInstance),
      value: newValue
    });
  },
  _addDisabledHiddenElement: function (handlerInstance) {
    if (handlerInstance.parentNode) {
      var value = this.getEditorValue(handlerInstance);
      if (handlerInstance._disabledHiddenElement) {
        handlerInstance._disabledHiddenElement.value = value;
      } else {
        var hiddenElement = new Element("input", {type: 'hidden', value: value, name: handlerInstance._name});
        handlerInstance._disabledHiddenElement = hiddenElement;
        handlerInstance._cell.appendChild(hiddenElement);
      }
    } else {
      // TODO: Onko tälläisiäkin tilanteita ????
    }
  },
  _removeDisabledHiddenElement: function (handlerInstance) {
    if (handlerInstance._disabledHiddenElement) {
      handlerInstance._disabledHiddenElement.remove();
      delete handlerInstance._disabledHiddenElement;
    }
  },
  _updateDisabledHiddenElement: function (handlerInstance, value) {
    if (handlerInstance._disabledHiddenElement) {
      handlerInstance._disabledHiddenElement.value = value;
    }
  },
  copyCellValue: function(target, source) {
    this.setEditorValue(target, this.getEditorValue(source));
  },
  _copyState: function (target, source) {
    this.copyCellValue(target, source);
    return this.setEditable(target, this.getEditable(source));
    // TODO: disabled, datatype yms tiedot
  },
  _unescapeHtmlEntities: function(value) {
    if (value) {
      var tmp = document.createElement("pre");
      tmp.innerHTML = value;
      value = tmp.firstChild.nodeValue;
    }
    return value;
  }
});

Object.extend(DataGridEditorController.prototype,fni.events.FNIEventSupport);